﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Xml;
using System.Xml.Linq;
using Microsoft.Office.Interop.OneNote;

namespace Norbauer.Office.OneNote
{

    // No point in refactoring this too much to a rich object model, because OneNote doesn't really open one up.

    class OneNoteApplicationConnection
    {
        private Application oneNote;
        public readonly XNamespace oneNoteDocumentXMLNamespace;

        public OneNoteApplicationConnection()
        {
            oneNote = new Microsoft.Office.Interop.OneNote.Application();

            // get XML namespace for OneNote docs
            string rawXMLfromOneNoteDocumentHierarchyScopedToRoot;
            oneNote.GetHierarchy(null, HierarchyScope.hsSelf, out rawXMLfromOneNoteDocumentHierarchyScopedToRoot);
            XDocument notebookXML = XDocument.Parse(rawXMLfromOneNoteDocumentHierarchyScopedToRoot);
            oneNoteDocumentXMLNamespace = notebookXML.Root.Name.Namespace;
        }


        #region class methods

        private static string writeXElementToXMLString(XElement element)
        {
            StringBuilder sb = new StringBuilder();
            XmlWriterSettings xws = new XmlWriterSettings();
            xws.OmitXmlDeclaration = true;
            using (XmlWriter xw = XmlWriter.Create(sb, xws))
            {
                element.Save(xw);
            }
            return sb.ToString();
        }

        #endregion


        #region public instance methods

        public XElement getCurrentPageAsXElement()
        {
            return getPageAsXElementByID(oneNote.Windows.CurrentWindow.CurrentPageId);
        }

        public XElement getPageAsXElementbyTitle(string titleOfRequestedPage)
        {
            return getPageAsXElementByID(getPageIDbyTitle(titleOfRequestedPage));
        }

        public void writePageAsXElementBackToDataStore(XElement pageAsXElement)
        {
            oneNote.UpdatePageContent(writeXElementToXMLString(pageAsXElement), System.DateTime.MinValue);
        }

        public string getURLForCurrentPage()
        {
            return getURLofOneNoteObject(oneNote.Windows.CurrentWindow.CurrentPageId);
        }

        public string getURLForFirstSelectedElementInCurrentPage()
        {
            XElement pageRoot = getCurrentPageAsXElement();

            IEnumerable<XElement> selectedXElementsCollection =
                from node in pageRoot.Descendants(oneNoteDocumentXMLNamespace + "OE")
                where ((string)node.Attribute("selected") == "all" || (string)node.Attribute("selected") == "partial")
                select node;

            XElement firstSelectedOE = selectedXElementsCollection.FirstOrDefault();
            string firstSelectedOEObjectID = firstSelectedOE.Attribute("objectID").Value;
            return getURLofOneNoteObject(oneNote.Windows.CurrentWindow.CurrentPageId, firstSelectedOEObjectID);
        }

        public string getTitleOfCurrentPageAsHtmlFragmentString()
        {
            XElement pageRoot = getCurrentPageAsXElement();
            // TODO use LINQ to select the first T element (descendent of a title) whose value isn't empty
            string pageTitle = pageRoot.Descendants(oneNoteDocumentXMLNamespace + "Title").FirstOrDefault().Descendants(oneNoteDocumentXMLNamespace + "T").FirstOrDefault().Value;
            return pageTitle;
        }

        #endregion


        #region private instance methods

        private string getURLofOneNoteObject(string pageID, string objectID = null)
        {
            string URL;
            oneNote.GetHyperlinkToObject(pageID, objectID, out URL);
            return URL;
        }

        private string getPageIDbyTitle(string titleOfRequestedPage)
        {
            string rawXMLfromOneNoteDocumentHierarchyScopedToPages;
            oneNote.GetHierarchy(null, HierarchyScope.hsPages, out rawXMLfromOneNoteDocumentHierarchyScopedToPages);
            XElement notebookHierarchyScopedToPages = XElement.Parse(rawXMLfromOneNoteDocumentHierarchyScopedToPages);

            var pageNodeForRequestedPageTitle = notebookHierarchyScopedToPages.Descendants(oneNoteDocumentXMLNamespace + "Page").Where(n =>
                n.Attribute("name").Value == titleOfRequestedPage).FirstOrDefault();
            if (pageNodeForRequestedPageTitle != null)
            {
                return pageNodeForRequestedPageTitle.Attribute("ID").Value;
            }
            else
            {
                // TODO raise exception
                // throw new RequestedNonExistentPageException();
                return null;
            }
        }

        private XElement getPageAsXElementByID(string pageToFetchID)
        {
            string pageXml;
            oneNote.GetPageContent(pageToFetchID, out pageXml, PageInfo.piSelection);
            XElement pageRoot = XElement.Parse(pageXml);
            return pageRoot;
        }

        #endregion

    }

}
